import {
  Descriptions,
  DescriptionsInstance,
  DescriptionsItem,
  Image,
  ImagePreviewGroup,
  Space,
} from "@arco-design/web-vue";
import { FunctionalComponent } from "vue/dist/vue.js";
import { assign, get, isFunction, isNil, pick } from "lodash-es";
import { DescItem } from "./type";
import components from "./components";

type UseDescriptionsReturn = [
  FunctionalComponent<DescriptionsInstance["$props"]>,
  { setData: (data: any) => void }
];

export default function useDescriptions(
  itemsConfig: DescItem[],
  defaultValue?: Recordable
): UseDescriptionsReturn {
  const data = ref(defaultValue ?? {});

  const setData = (_data: any) => {
    assign(data.value, _data);
  };

  const Desc: FunctionalComponent<DescriptionsInstance["$props"]> = (props) => {
    return (
      <Descriptions {...props}>
        {itemsConfig.map((item) => (
          <DescriptionsItem {...pick(item, "label", "span")}>
            {(() => {
              const value = get(data.value, item.path);
              if (isNil(value) && !item.render) return;
              if (item.component == "ImageList") {
                const imageSize = item.imageSpan ?? 72;
                return (
                  <ImagePreviewGroup infinite>
                    <Space size={16}>
                      {value &&
                        (value as string[]).map((image) => (
                          <Image
                            src={image}
                            width={imageSize}
                            height={imageSize}
                            style="cursor: pointer"
                          />
                        ))}
                    </Space>
                  </ImagePreviewGroup>
                );
              } else if (item.component) {
                // 这里实在是不知道 Comp 标注什么类型合适，故断言为 any
                const Comp = components[item.component] as any;
                const _props: Recordable = item.componentProps ?? {};
                ["color"].forEach((p: any) => {
                  if (isFunction((item.componentProps as Recordable)[p]))
                    _props[p] = (item.componentProps as Recordable)[p](value);
                });
                return <Comp {..._props}>{item.mapping?.(value) ?? value}</Comp>;
              } else if (item.render) {
                return item.render();
              } else {
                return <>{value}</>;
              }
            })()}
          </DescriptionsItem>
        ))}
      </Descriptions>
    );
  };

  return [Desc, { setData }];
}
